// const axios = require('axios');
const { promisify } = require('util');
const path = require('path');
const fs = require('fs');
const ncp = require('ncp');
const ora = require('ora');
const inquirer = require('inquirer');
const metalsmith = require('metalsmith');
const { render } = require('consolidate').ejs;
const download = require('download-git-repo');
const axios = require('axios-https-proxy-fix');
const myAxios = axios.create({
  baseURL: 'https://api.github.com',
  headers: { "Authorization": 'token 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' },
  proxy: {
    host: '127.0.0.1',
    port: 1087
  },
});
const myDownload = promisify(download);// promise化
const author = "BoreyLee";
/**
 * 给方法添加loading
 * @param {*} fn 
 * @returns 
 */
const addLoading = function (fn) {
  return async function (...args) {
    const spinner = ora('正在下载...');
    spinner.start();
    try {
      let res = await fn(...args);
      spinner.succeed('下载成功');
      return res;
    } catch (error) {
      spinner.fail('下载失败');
    }
  }
}

/**
 * 获取仓库列表
 * @returns 
 */
const getRepos = async function () {
  const { data } = await myAxios.get(`/users/${author}/repos`)

  const repos = data.map(item => item.name);

  return repos;
}

/**
 * 获取版本号列表
 * @param {*} repo 
 * @returns 
 */
const getTags = async function (repo) {
  const { data } = await myAxios.get(`/repos/${author}/${repo}/tags`)

  const tags = data.map(item => item.name);

  return tags
}

/**
 * 执行下载
 * @param {*} repo 
 * @param {*} tag 
 */
const downloadRepo = async function (repo, tag) {
  // const { platform, env } = process;
  // const cacheDir = `${env[platform === 'win32' ? 'USERPROFILE' : 'HOME']}/.tmp`;// 存放缓存地址
  // download-git-repo导出规则user/repo#tag
  let api = `${author}/${repo}`;
  if (tag) api += `#${tag}`;
  const desc = path.resolve(__dirname, '../.tmp', repo);
  console.log(desc)
  const flag = fs.existsSync(desc);// 缓存中是否存在模版
  return flag ? desc : await addLoading(myDownload)(api, desc);// 需要翻墙
}

module.exports = async ([proname]) => {
  let repos = await addLoading(getRepos)();// 获取仓库列表
  const { repo } = await inquirer.prompt({
    type: 'list',
    choices: repos,
    message: '请选择目标仓库模版',
    name: 'repo'
  });
  let tags = await addLoading(getTags)(repo);// 获取版本号列表
  let desc = null;
  if (tags && tags.length) {
    const { tag } = await inquirer.prompt({
      type: 'list',
      choices: tags,
      message: '请选择目标版本号',
      name: 'tag'
    });
    desc = await downloadRepo(repo, tag);
  } else {
    const { isDownload } = await inquirer.prompt({
      type: 'confirm',
      message: '当前仓库不存在多个版本是否直接下载',
      name: 'isDownload'
    });
    if (!isDownload) return;
    desc = await downloadRepo(repo);
  }

  if (fs.existsSync(path.join(desc, 'que.js'))) {
    // 需要渲染数据
    await new Promise((resolve, reject) => {
      metalsmith(__dirname)
        .source(desc)
        .destination(path.resolve(proname))
        .use(async (files, metal, done) => {
          // files 需要渲染模版目录下的所有文件
          const quesArr = require(path.join(desc, 'que.js'));
          const answers = await inquirer.prompt(quesArr)
          let meta = metal.metadata();
          Object.assign(meta, answers);// 插入询问内容
          delete files['que.js'];// 删除提问文件
          done();
        })
        .use((files, metal, done) => {
          let meta = metal.metadata();
          Reflect.ownKeys(files).forEach(async (item) => {
            if (item.includes('js') || item.includes('json')) {
              let content = files[item].contents.toString();
              if (content.includes("<%")) {
                content = await render(content, meta);
                files[item].contents = Buffer.from(content)
              }
            }
          });
          done();
        })
        .build((err) => {
          if (err) {
            reject();
          } else {
            resolve();
          }
        })
    })
  } else {
    // 直接复制模版
    ncp(desc, proname)
  }
  console.log('项目创建成功!')
}

